import org.junit.jupiter.api.Test;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

/**
 * @author xufeng
 * @date 2023-04-27
 */
public class LocalDateTimeDemo {
    /**
     * MAX：localDateTime对象能表示的最大值。
     * MIN：localDateTime对象能表示的最小值。
     */
    @Test
    public void test01(){
        System.out.println(LocalDateTime.MAX); // 输出 +999999999-12-31T23:59:59.999999999
        System.out.println(LocalDateTime.MIN); // 输出 -999999999-01-01T00:00
    }
}
class LocalDateTimeDemo01{
    /**
     * from(TemporalAccessor temporal)
     * 作用：从其他含有日期和时间数据的时间类中获取localDateTime对象。
     */
    @Test
    public void test01(){
        ZonedDateTime zonedDateTime01 = ZonedDateTime.parse("2023-01-01T10:00:00+08:00[Asia/Shanghai]");
        LocalDateTime localDateTime01 = LocalDateTime.from(zonedDateTime01);
        System.out.println(localDateTime01); // 输出 2023-01-01T10:00
    }

    /**
     * now()
     * 作用：从操作系统获取日期和时间数据。
     *
     * now(Clock clock)
     * 作用：获取其他时区此刻的日期和时间。
     *
     * now(ZoneId zone)
     * 作用：从clock对象获取时间数据。clock对象有时区的概念，所以获取的是指定地区的日期和时间。
     */
    @Test
    public void test02(){
        System.out.println(LocalDateTime.now()); // 输出 2023-05-08T19:43:44.130

        ZoneId zoneId01 = ZoneId.of("America/Los_Angeles");
        System.out.println(LocalDateTime.now(zoneId01)); // 输出 2023-05-08T04:43:44.132

        Instant instant01 = Instant.parse("2023-04-01T10:00:00Z");
        Clock fixedClock01 = Clock.fixed(instant01, zoneId01);
        System.out.println(LocalDateTime.now(fixedClock01)); // 输出 2023-04-01T03:00
    }

    /**
     * of(int year, int month, int dayOfMonth, int hour, int minute)
     * of(int year, int month, int dayOfMonth, int hour, int minute, int second)
     * of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond)
     * of(int year, Month month, int dayOfMonth, int hour, int minute)
     * of(int year, Month month, int dayOfMonth, int hour, int minute, int second)
     * of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond)
     * of(LocalDate date, LocalTime time)
     * 作用：根据给定的日期和时间数据创建localDateTime对象。
     *
     * ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset)
     * 作用：给定距离EPOCH时间的相关数据创建localDateTime对象。
     *
     * ofInstant(Instant instant, ZoneId zone)
     * 作用：instant是一个时间戳对象，表示距离EPOCH时间的秒数，zone表示时区。
     */
    @Test
    public void test03(){
        LocalDateTime dateTime01 = LocalDateTime.of(2023, 1, 1, 12, 30, 45, 100);
        System.out.println(dateTime01); // 输出 2023-01-01T12:30:45.000000100

        LocalDate date01 = LocalDate.of(2023, 1, 1);
        LocalTime time01 = LocalTime.of(12, 30, 45, 100);
        LocalDateTime dateTime02 = LocalDateTime.of(date01, time01);
        System.out.println(dateTime02); // 输出 2023-01-01T12:30:45.000000100

        LocalDateTime dateTime03 = LocalDateTime.ofEpochSecond(1, 100, ZoneOffset.of("+00:00"));
        System.out.println(dateTime03); // 输出 1970-01-01T00:00:01.000000100

        Instant instant01 = Instant.parse("2023-01-01T10:00:00Z");
        ZoneId zoneId = ZoneId.of("Asia/Shanghai");
        LocalDateTime dateTime04 = LocalDateTime.ofInstant(instant01, zoneId);
        System.out.println(dateTime04); // 输出 2023-01-01T18:00
    }

    /**
     * parse(CharSequence text)
     * parse(CharSequence text, DateTimeFormatter formatter)
     * 作用：将字符串解析成localDateTime对象，默认格式yyyy-MM-ddTHH:mm:ss，formatter用来指定字符串格式。
     */
    @Test
    public void test04(){
        System.out.println(LocalDateTime.parse("2023-01-01T12:30:45")); // 输出 2023-01-01T12:30:45

        DateTimeFormatter df01 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
        System.out.println(LocalDateTime.parse("2023年01月01日 12时30分45秒", df01)); // 输出 2023-01-01T12:30:45
    }
}

class LocalDateTimeDemo02{

    /**
     * atOffset(ZoneOffset offset)
     * atZone(ZoneId zone)
     * 作用：分别为localDateTime添加偏移量或时区的概念，使其转换成offsetDateTime对象或zonedDateTime对象。
     *      注意，不管是添加偏移量还是时区，只跟原来的localDateTime对象组合，不改变日期和时间数据。
     */
    @Test
    public void test01(){
        LocalDateTime dateTime01 = LocalDateTime.parse("2023-01-01T10:00:00");
        ZoneOffset zoneOffset01 = ZoneOffset.of("+08:00");
        ZoneId zoneRegion01 = ZoneId.of("Asia/Shanghai");
        OffsetDateTime offsetDateTime01 = dateTime01.atOffset(zoneOffset01);
        ZonedDateTime zonedDateTime01 = dateTime01.atZone(zoneRegion01);
        System.out.println(dateTime01); // 输出 2023-01-01T10:00
        System.out.println(offsetDateTime01); // 输出 2023-01-01T10:00+08:00
        System.out.println(zonedDateTime01); // 输出 2023-01-01T10:00+08:00[Asia/Shanghai]
    }

    /**
     * toLocalDate()
     * toLocalTime()
     * 作用：分别从localDateTime对象获取日期数据或时间数据。
     */
    @Test
    public void test02(){
        LocalDateTime dateTime01 = LocalDateTime.parse("2023-01-01T12:30:45");
        System.out.println(dateTime01.toLocalDate()); // 输出 2023-01-01
        System.out.println(dateTime01.toLocalTime()); // 输出 12:30:45
    }

    /**
     * truncatedTo(TemporalUnit unit)
     * 作用：根据时间单位截取localDateTime对象，看源码近支持截取localTime对象。
     */
    @Test
    public void test03(){
        LocalDateTime dateTime01 = LocalDateTime.parse("2023-01-01T12:30:45");
        System.out.println(dateTime01.truncatedTo(ChronoUnit.MINUTES)); // 输出 2023-01-01T12:30
        System.out.println(dateTime01.truncatedTo(ChronoUnit.HOURS)); // 输出 2023-01-01T12:00
        System.out.println(dateTime01.truncatedTo(ChronoUnit.DAYS)); // 输出 2023-01-01T00:00
        System.out.println(dateTime01.truncatedTo(ChronoUnit.MONTHS)); // 异常：Unit is too large to be used for truncation
    }

    /**
     * until(Temporal endExclusive, TemporalUnit unit)
     * 作用：根据时间单位计算两个localDateTime对象的差值。
     */
    @Test
    public void test04(){
        LocalDateTime dateTime01 = LocalDateTime.parse("2023-01-01T00:00:00");
        LocalDateTime dateTime02 = LocalDateTime.parse("2023-01-02T00:00:00");
        System.out.println(dateTime01.until(dateTime02, ChronoUnit.DAYS)); // 输出 1
        System.out.println(dateTime01.until(dateTime02, ChronoUnit.SECONDS)); // 输出 86400
    }
}